package grpc_proxy_middleware

import (
	"context"
	"strings"

	"gin-gateway/core/utils"
	"gin-gateway/core/dao"
	"github.com/pkg/errors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"log"
)

// jwt app租户 auth JwtToken
func GrpcJwtAuthTokenMiddleware(serviceDetail *dao.ServiceDetail) func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
	return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		md, ok := metadata.FromIncomingContext(stream.Context()) // 这里拿到的是 context 中经过深拷贝后的数据
		if !ok {
			return errors.New("miss metadata from context")
		}
		auths := md.Get("authorization")
		authToken := ""
		if len(auths) > 0 {
			authToken = auths[0]
		}

		// fmt.Println(auths)
		JwtToken := strings.ReplaceAll(authToken, "Bearer ", "")
		if JwtToken == "" {
			return errors.New("app authToken is nil")
		}

		appMatched := false
		claims, err := utils.JwtDecode(JwtToken)
		if err != nil {
			return errors.WithMessage(err, "JwtDecode")
		}

		var appJsonStr string
		appInfo, exists := dao.AppManagerHandler.InAppMap(claims.Issuer)
		if exists && appInfo.AppID == claims.Issuer {
			// md.Set("app", utils.Obj2Json(appInfo))
			appJsonStr = utils.Obj2Json(appInfo)
			appMatched = true
		}

		if !appMatched {
			return errors.WithMessage(err, "jwt validate fail,not match valid app")
		}

		// 在处理器之间传递数据只能用 context，不能用 md.Set，
		ctx := context.WithValue(stream.Context(), "appInfo", appJsonStr)
		if err = handler(srv, &wrappedSS{ServerStream: stream, Ctx: ctx}); err != nil {
			log.Println("GrpcJwtAuthTokenMiddleware failed with error :", err)
			return err
		}
		return nil
	}
}

type wrappedSS struct {
	grpc.ServerStream
	Ctx context.Context
}

func (w *wrappedSS) Context() context.Context {
	return w.Ctx
}
